package com.cdks.wuxiu.api.component.aspect;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.json.JSONUtil;

import com.cdks.wuxiu.api.util.AuthUtils;
import com.cdks.wuxiu.common.util.ServletUtils;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * 统一日志处理切面
 */
@Slf4j
@Aspect
@Component
public class LogAspect {
    /**
     * LOG TEMPLATE
     * {METHOD} - {URL} - ARGS : {} - HEADER : {} - IP : {} - SPEND TIME : {}
     */
    private static final String LOG_TEMPLATE = "{} : {} - ARGS : {} - HEADER : {} - IP : {} - SPEND TIME : {}";

    
    @Around("execution(public * com.cdks.wuxiu.api.controller..*.*(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 记录开始时间
        long startTime = System.currentTimeMillis();
        // 请求
        HttpServletRequest request = ServletUtils.getRequest();
        // 记录请求内容
        String method = request.getMethod();
        String url = request.getRequestURL().toString();
        String args = JSONUtil.toJsonStr(getNameAndValue(joinPoint));
        String header = JSONUtil.toJsonStr(AuthUtils.getCommonHeader());
        String ip = ServletUtil.getClientIP(request);

        try {
            // 执行请求方法
            return joinPoint.proceed(joinPoint.getArgs());
        } finally {
            // 记录结束时间
            long endTime = System.currentTimeMillis();
            // {METHOD} - {URL} - ARGS : {} - HEADER : {} - IP : {} - SPEND TIME : {}
            log.info(LOG_TEMPLATE, method, url, args, header, ip, endTime - startTime);
        }
    }

    /**
     * 获取切入方法参数
     */
    Map<String, Object> getNameAndValue(ProceedingJoinPoint joinPoint) {
        Map<String, Object> param = new HashMap<>();
        Object[] paramValues = joinPoint.getArgs();
        
        for (Object paramValue : paramValues) {
            Map<String, Object> map = BeanUtil.beanToMap(paramValue);
            param.putAll(map);
        }

        return param;
    }
}
